#include "coloringcanvas.h"

#include <QtDeclarative>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include "drmimageprovider.h"

ColoringCanvas::ColoringCanvas(QDeclarativeItem *parent):
        QDeclarativeItem(parent)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);
}

void ColoringCanvas::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    painter->drawImage(option->rect, image_);
}

void ColoringCanvas::setColor(const QColor newColor)
{
    if (color_ != newColor)
    {
        color_ = newColor;
        emit colorChanged();
    }
}

void ColoringCanvas::setSource(const QString& newSource)
{
    if (source_.compare(newSource))
    {
        source_ = newSource;

        DrmImageProvider provider;
        QImage image = provider.requestImage(newSource,0,QSize(580,360));

        image_ = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, Qt::ColorOnly);

        update();
        emit sourceChanged();
    }
}

void ColoringCanvas::click(int x, int y)
{
    QPoint fill;
    if (check(QPoint(x, y), fill))
    {
        floodFill(fill, color_.rgb());
        update();
    }
}

bool ColoringCanvas::check(const QPoint& point, QPoint& valid)
{
    if (!image_.rect().contains(point)) return false;
    if (image_.pixel(point) != ignore_.rgb())
    {
        valid = point;
        return true;
    }
    return false;
}

bool ColoringCanvas::test(const QPoint& point, const QRgb& color)
{
    if (!image_.rect().contains(point)) return false;
    return (image_.pixel(point) == color);
}

void ColoringCanvas::drawHorizontalLine(const QPoint & p1, const QPoint & p2, const QRgb& fillColor)
{
    int x1 = p1.x();
    int x2 = p2.x();
    int y = p1.y();

    if (x1 > x2)
    {
        int temp = x1;
        x1 = x2;
        x2 = temp;
    }

    uchar* bytes = image_.scanLine(y);
    int* p = (int*)bytes;

    for (int i = x1; i <= x2; i++)
    {
        p[i] = fillColor;
    }
}

void ColoringCanvas::floodFill(const QPoint& point, const QRgb& fillColor)
{
    if (!image_.rect().contains(point)) return;
    QRgb target = image_.pixel(point);
    if (target == fillColor) return;

    QStack<QPoint> stack;
    QPoint p;

    stack.reserve(1000);
    stack.push(point);

    while (!stack.isEmpty())
    {
        p = stack.pop();
        QPoint w = p;
        QPoint e = p;
        if (test(p + QPoint(0, 1), target))
            stack.push(p + QPoint(0, 1));
        if (test(p + QPoint(0, -1), target))
            stack.push(p + QPoint(0, -1));
        while (test(w + QPoint(-1, 0),target) && w.x() > 0)
        {
            w += QPoint(-1, 0);
            if (test(w + QPoint(0, 1), target))
                stack.push(w + QPoint(0, 1));
            if (test(w + QPoint(0, -1), target))
                stack.push(w + QPoint(0, -1));
        }

        while (test(e + QPoint(1, 0), target) && e.x() < image_.width()-1)
        {
            e += QPoint(1, 0);
            if (test(e + QPoint(0, 1), target))
                stack.push(e + QPoint(0, 1));
            if (test(e + QPoint(0, -1), target))
                stack.push(e + QPoint(0, -1));
        }

        drawHorizontalLine(w, e, fillColor);
    }
}
